<!DOCTYPE html>
<html lang="zh-cn"><head>
<title>RainbowC0&#39;s Blog - 测试 GNU Octave 各种遍历的时间效率</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<meta name="description"
    content="GNU Octave 是 MATLAB 的一个开源替代品，对 MATLAB 代码的兼容性很好，但是运行效率较慢。MATLAB 采用即时编译技术 (Just in Time, JIT) 以及 Intel MKL (Math Kernel Library) 加速计算， ">
<link rel="canonical" href="https://rainbowc0.gitee.io/post/efficency-of-loop-in-octave/" />

<link rel="icon" type="image/x-icon" href="/favicon/favicon.ico">
  



	<link rel="stylesheet"
  href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/solarized-light.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"></script>

<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/languages/matlab.min.js"></script>


<script>hljs.initHighlightingOnLoad();</script>

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/normalize.css@8.0.1/normalize.css">

<link rel="stylesheet" href="https://unpkg.com/purecss@2.0.6/build/pure-min.css">







<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/css/all.css">



<link rel="stylesheet" href="/css/hugo-tufte.min.css">

<link rel="stylesheet"  href="/css/hugo-tufte-override.css">



</head>
<body >
        
<div id="layout" class="pure-g">
  <article class="pure-u-1">
    <header class="brand">
  <a href="https://rainbowc0.gitee.io/"><h1>RainbowC0&#39;s Blog</h1></a>
  <h2>惟精惟一，允执厥中。</h2>
  <nav class="menu">
    <ul>
    
        <li><a href="/"><i class="fas fa-home la-lg"></i>HOME</a></li>
    
        <li><a href="/post"><i class="fas fa-book" fa-lg></i>POSTS</a></li>
    
        <li><a href="/categories"><i class="fas fa-tag fa-lg"></i>CATEGORIES</a></li>
    
        <li><a href="/tags"><i class="fas fa-tags fa-lg"></i>TAGS</a></li>
    
        <li><a href="/about"><i class="fas fa-info-circle fa-lg"></i>ABOUT</a></li>
    
        <li><a href="https://gitee.com/RainbowC0/RainbowC0"><i class="fab fa-github fa-lg"></i>SOURCE CODE</a></li>
    
    </ul>
</nav>

  <hr />
</header>

    <section>
  
  <h1 class="content-title">
    
    <a href="/post/efficency-of-loop-in-octave/">测试 GNU Octave 各种遍历的时间效率</a>
    
  </h1>
  
    
    
      <span class="content-meta">
        
    
            
        
          <i class="fa fa-calendar"></i>
          &nbsp;Sep 11, 2023
        
    
        
          &nbsp;<i class="fa fa-clock-o"></i>
          &nbsp;2 min read
        
    
        
          <br>
          <i class="fa fa-tags"> </i>
          
            <a  href="https://rainbowc0.gitee.io/categories/%E6%95%B0%E5%AD%A6%E5%BB%BA%E6%A8%A1">数学建模</a>
          
        
      </span>
    
  
  </section>
    
<section>
  <details closed class="toc">
    <summary>Contents</summary>
    <nav id="TableOfContents">
  <ul>
    <li><a href="#测试代码结构">测试代码结构</a></li>
    <li><a href="#for-循环">for 循环</a></li>
    <li><a href="#arrayfun-遍历">arrayfun 遍历</a></li>
    <li><a href="#直接计算矩阵批量计算">直接计算/矩阵批量计算</a></li>
    <li><a href="#调用-c-语言的循环">调用 C 语言的循环</a></li>
    <li><a href="#直接计算-ii">直接计算 II</a></li>
    <li><a href="#小结">小结</a></li>
  </ul>
</nav>
  </details>
</section>


    <section><p>GNU Octave 是 MATLAB 的一个开源替代品，对 MATLAB 代码的兼容性很好，但是运行效率较慢。MATLAB 采用即时编译技术 (Just in Time, JIT) 以及 Intel MKL (Math Kernel Library) 加速计算，</p>
<p>但是 GNU Octave 并没有这些技术<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>。而拉低效率的主要是遍历/循环操作，因此对相关遍历操作进行比较。</p>
<hr>
<h2 id="测试代码结构">测试代码结构</h2>
<p>给定一个 9999x1 的随机数矩阵 b，计算测试效率。</p>
<pre><code class="language-MATLAB">% 预执行
tic
b = randn(9999,1);

% 测试部分，计算正弦（单位：度）
a = toc;
loop
  sin(b*pi/180);
endloop
toc - a
</code></pre>
<h2 id="for-循环">for 循环</h2>
<p><code>for</code> 循环可能是所有方法中最慢的，至少比常规的矩阵批量计算慢。</p>
<p>代码如下：</p>
<pre><code class="language-MATLAB">a=toc;
for i=1:9999
  sin(d*pi/180);
end
toc-a
</code></pre>
<p>测试结果多为 9.2e-3。</p>
<h2 id="arrayfun-遍历">arrayfun 遍历</h2>
<p><code>arrayfun</code> 是一个函数，将一个可遍历下标访问的集合的每一个元素作为函数的参数，并执行函数。</p>
<pre><code class="language-MATLAB">a=toc;
arrayfun(@(x)sin(x*pi/180), b);
toc-a
</code></pre>
<p>测试结果多为 0.035，比 <code>for</code> 循环慢。</p>
<h2 id="直接计算矩阵批量计算">直接计算/矩阵批量计算</h2>
<p>MATLAB/GNU Octave 的很多函数本身就是针对矩阵的，<code>sin</code> 函数同样可以批量计算矩阵的每个值的正弦值。</p>
<p>代码如下：</p>
<pre><code class="language-MATLAB">a=toc
sin(b*pi/180);
toc-a
</code></pre>
<p>测试结果多为 3e-4，目前最快。</p>
<h2 id="调用-c-语言的循环">调用 C 语言的循环</h2>
<p>GNU Octave 是可以通过 .oct 或者 .mex 文件调用 C 语言的，而这两种文件实质上是动态链接库文件（.so 文件）。理论上用 C 语言的循环会快很多。</p>
<p>代码如下：</p>
<ul>
<li>C 代码</li>
</ul>
<pre><code class="language-c">#include &quot;mex.h&quot;
#include&lt;math.h&gt;

void
mexFunction (int nlhs, mxArray *plhs[],
             int nrhs, const mxArray *prhs[])
{
  mwSize n;
  mwIndex i;
  double *vri, *vro;

  if (nrhs != 1 || ! mxIsDouble (prhs[0]) || mxIsComplex(prhs[0]))
    mexErrMsgTxt (&quot;ARG1 must be a double radio matrix&quot;);

  n = mxGetNumberOfElements (prhs[0]);
  plhs[0] = mxCreateNumericArray (mxGetNumberOfDimensions (prhs[0]),
                                  mxGetDimensions (prhs[0]),
                                  mxGetClassID (prhs[0]),
                                  0);
  vri = mxGetPr (prhs[0]);
  vro = mxGetPr (plhs[0]);

  for (i = 0; i &lt; n; i++)
    vro[i] = sin(vri[i]*M_PI/180.);
}
</code></pre>
<p>编译用命令：</p>
<pre><code class="language-plain">mkoctfile --mex func.c -o mysind -lm
</code></pre>
<ul>
<li>GNU Octave 代码：</li>
</ul>
<pre><code class="language-MATLAB">a=toc;
mysind(b);
toc-a
</code></pre>
<p>测试结果多为 3.2e-4，略逊于直接计算。</p>
<h2 id="直接计算-ii">直接计算 II</h2>
<p>其实 GNU Octave/MATLAB 还有一个直接计算角度正弦的函数 <code>sind</code>，不过这个函数是由一个 <code>.m</code> 文件定义的，而不是内建函数，会有一些多余的判断。测试用该函数直接计算。</p>
<pre><code class="language-MATLAB">a=toc;
sind(b);
toc-a
</code></pre>
<p>测试结果多为 6.6e-4，明显高于上两者。</p>
<hr>
<h2 id="小结">小结</h2>
<p>测试验证了 <code>arrayfun</code> 循环的确效率最慢，而内建函数+矩阵批量计算效率最高，同时发现调用 C 语言的效率略有提升，而一些 <code>.m</code> 文件定义的函数在保证代码健壮性的同时损失了部分效率。所以 GNU Octave/MATLAB 能用矩阵批量计算的尽量用！</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>GNU Octave 在早期一些版本使用的 LLVM 的 JIT 技术，但是随着 LLVM 的频繁更新， GNU Octave 的新版本难以适配不断更新的 LLVM，最终弃用。见：<a href="https://wiki.octave.org/JIT">https://wiki.octave.org/JIT</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div></section>
    <section>
      <footer class="page-footer">
		<hr>

    <div class="previous-post" style="display:inline-block;">
      
      <a class="link-reverse" href="https://rainbowc0.gitee.io/post/run-x86-on-linux-arm64/?ref=footer">« 在 Linux ARM64 上高效运行 x86 程序：Box86</a>
      
    </div>

    <div class="next-post", style="display:inline-block;float:right;">
      
      <a class="link-reverse" href="https://rainbowc0.gitee.io/post/github-page-to-bing/?ref=footer">将 Github Pages 个人博客录入搜索引擎（以 Bing 为例） »</a>
      
    </div>

		<ul class="page-footer-menu">

      
      

      
      <li><a href="https://github.com/RainbowC0"><i class='fab fa-github fa-lg'></i></a></li>
      

      

      

      

      

      

      

      

      

      

      
      
      
		</ul>

  

	<div class="copyright">
	<p>
    
      &copy; 2024
    .
    All rights reserved.
    
  </p>
</div>
</footer>

    </section>
  </article>
</div>

    </body>

</html>